package com.c.util;

import java.util.Date;
import java.util.UUID;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import com.ning.http.client.AsyncHttpClient;
import com.ning.http.client.AsyncHttpClient.BoundRequestBuilder;
import com.ning.http.client.AsyncHttpClientConfig;
import com.ning.http.client.Response;

import cn.hutool.json.JSONUtil;

@Service
public class CommuncationService {

	private static Logger logger = LoggerFactory.getLogger(CommuncationService.class);

	@Value("${notification.curb}")
	private Integer notificationCurb;

	// 接受https的任何证书
	private static AsyncHttpClient asyncHttpClient = new AsyncHttpClient(
			new AsyncHttpClientConfig.Builder().setMaxConnectionsPerHost(10).setMaxConnections(50)
					.setConnectTimeout(1500).setRequestTimeout(1500).setAcceptAnyCertificate(true).build());

	private static ThreadPoolTaskExecutor notifyTaskThreadPool = new ThreadPoolTaskExecutor();

	static {

		// 线程池所使用的缓冲队列
		notifyTaskThreadPool.setQueueCapacity(500);

		// 线程池维护线程的最少数量
		notifyTaskThreadPool.setCorePoolSize(5);

		// 线程池维护线程的最大数量
		notifyTaskThreadPool.setMaxPoolSize(100);

		// 线程池维护线程所允许的空闲时间
		notifyTaskThreadPool.setKeepAliveSeconds(30000);

		notifyTaskThreadPool.initialize();
	}

	public void notification(final String bizId, final String apiName, final String operatorId, final Object param,
			final boolean curb) {

		final String notificationId = UUID.randomUUID().toString();

		final Long startTime = new Date().getTime();

		logger.info("[{}]-[{}]-[{}]-[{}]-准备推送,正在执行的任务数:{}",
				new Object[] { apiName, operatorId, bizId, notificationId, notifyTaskThreadPool.getActiveCount() });

		notifyTaskThreadPool.execute(new Runnable() {

			@Override
			public void run() {

				logger.info("[{}]-[{}]-[{}]-[{}]-开始推送,推送内容:[{}]",
						new Object[] { apiName, operatorId, bizId, notificationId, JSONUtil.parse(param) });

				try {
					request(notificationId, apiName, operatorId, param, null, curb);
				} catch (Exception e) {
				}

				long delayTime = new Date().getTime() - startTime;

				// 如果延迟时间>10秒,则打异常log
				if (delayTime > 10000) {
					logger.error("[{}]-[{}]-[{}]-[{}]-推送内容:{},推送延迟:{} ms", new Object[] { apiName, operatorId, bizId,
							notificationId, JSONUtil.parse(param), delayTime });
				} else {
					logger.info("[{}]-[{}]-[{}]-[{}],推送延迟:{} ms",
							new Object[] { apiName, operatorId, bizId, notificationId, delayTime });
				}
			}
		});
	}

	/**
	 * 
	 * /** 数据推送接口
	 *
	 * @param apiName
	 *            推送接口名
	 * @param operatorId
	 *            推送平台运营商id
	 * @param param
	 *            需推送的数据对象（务必传对象，不要传json串）
	 * @return 互联互通标准对象中的data
	 */
	private void request(final String traceId, String apiName, String operatorId, Object param,
			ResponseCallback<?> callback, final boolean curb) {

		// 支持推送多个url
		{
			String[] urls = null;
			for (String url : urls) {

				// 防止单个url失败,导致推送不全
				try {

					String tokenCurbTime = null;

					logger.info("[{}]-开始推送url:{},熔断时间:{},推送启用熔断机制:{},环境是启用熔断机制:{}",
							new Object[] { traceId, url, tokenCurbTime, curb, notificationCurb == 1 });

					// 如果存在熔断,且请求支持熔断
					if (StringUtils.isNotBlank(tokenCurbTime) && curb && notificationCurb == 1) {
						logger.info("[{}]-[{}]-[{}]-[熔断],熔断结束时间:{}",
								new Object[] { traceId, operatorId, apiName, tokenCurbTime });
					} else {
						request(traceId, url, apiName, param, 1, 0, callback);
					}
				} catch (Exception e) {
				}
			}
		}
	}

	private <T> void request(String traceId, String serverUrl, String apiName, Object param, int tryCnt,
			Integer refreshTokenCnt, ResponseCallback<T> callback) {

		String url = serverUrl + apiName;

		try {
			String paramStr = JSONUtil.toJsonStr(param);

			logger.info("[{}]-访问url:{},开始获取token", new Object[] { traceId, url });

			// 获得token
			String token = null;

			if (StringUtils.isBlank(token)) {
				return;
			}

			BoundRequestBuilder requestBuilder = asyncHttpClient.preparePost(url).addHeader("Content-type",
					"application/json;charset=utf-8");

			if (StringUtils.isNotBlank(token)) {
				requestBuilder.addHeader("Authorization", "Bearer " + token);
			}

			logger.info("[{}]-开始请求数据", new Object[] { traceId });

			// 参数请求做加密
			Response httpResponse = requestBuilder.setBody("").execute().get();

			logger.info("[{}]-请求数据完成,返回状态码:{}", new Object[] { traceId, httpResponse.getStatusCode() });

			// 如果返回正常,则开始解析
			if (httpResponse.getStatusCode() == 200) {

				logger.info("[{}]-开始解析返回结果:{}", new Object[] { traceId, httpResponse.getResponseBody() });

				// 解密返回报文 TODO 这里解签应该用对方的秘钥

				// 如果token失效且是第一次失效token,则增加重试次数
				if ("4002".equals(String.valueOf("")) && refreshTokenCnt == 0) {
					logger.info("[{}]-token失效,重新请求", new Object[] { traceId });
					refreshTokenCnt++;
					tryCnt++;
				}

			}
		} catch (Exception e) { // 这里接口请求只认为是info,防止error log 太大
		}

		// 如果设置了尝试次数,则进行递归尝试
		if (--tryCnt > 0) {
			request(traceId, serverUrl, apiName, param, tryCnt, refreshTokenCnt, callback);
		}
	}

	public interface ResponseCallback<T> {

		// public <T> T call(int responseStatus, EvcsResponse evcsResponse);

	}

	// private (){
	//
	// EvcsResponse response = new EvcsResponse();
	//
	// }

}
